﻿#include <sys/epoll.h>
using namespace SocketLib;

template<typename SOCKETSTRUCT>
EpollServer<SOCKETSTRUCT>::EpollServer(int num)
{
    m_epollFD = epoll_create(256);
    m_clientNum = 0;

    // 申请链接资源
    m_socketPoll.init(num);
    SOCKETSTRUCT* pMemory = m_socketPoll.getMemory();

    for(int i = 0; i < num; ++i)
    {
        _setServer(pMemory[i]);
    }
}

template<typename SOCKETSTRUCT>
EpollServer<SOCKETSTRUCT>::~EpollServer()
{
    if(m_epollFD != -1)
    {
        close(m_epollFD);
    }
}

template<typename SOCKETSTRUCT>
SOCKETSTRUCT* EpollServer<SOCKETSTRUCT>::getSocketBuffer()
{
    return m_socketPoll.getMemory();
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_auxHandlerNewClient(sock clientSocket)
{
    SOCKETSTRUCT* newClient = m_socketPoll.popPtrElement();
    if(NULL != newClient)
    {
        _setSocketOnConnected(*newClient, clientSocket);
        // 监听可读事件
        addFDEvent(newClient, EPOLLET | EPOLLIN);

        // 加入到可写列表
        _insertWriteable(newClient);
        newClient->onConnection();
    }
    else
    {
        cout << "not have resource, please close socket" << endl;
        SocketLib::SocketApi::CloseSocket(clientSocket);
    }
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_handlerAcceptList()
{
    if(m_acceptedList.currentWriteSize() > 0)
    {
        vector<sock>& refList = m_acceptedList.getReadList();
        int num = refList.size();
        if(num > 0)
        {
            for(int i = 0; i < num; ++i)
            {
                _auxHandlerNewClient(refList[i]);
            }

            refList.clear();
        }
    }
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_handlerCloseList()
{
    if(m_mustCloseList.currentWriteSize() > 0)
    {
        vector<BaseSocket*>& refList = m_mustCloseList.getReadList();

        int closeSize = refList.size();
        if(closeSize > 0)
        {
            for(int i = 0; i < closeSize; ++i)
            {
                SOCKETSTRUCT* p = (SOCKETSTRUCT*)refList[i];
                if(NULL != p)
                {
                    _disConnection(p);
                }
            }

            refList.clear();
        }
    }
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_handlerEpollEvent(int AOverTime)
{
    epoll_event events[128];
    int    nfds = epoll_wait(m_epollFD, events, sizeof(events) / sizeof(epoll_event), AOverTime);

    for(int i = 0; i < nfds; ++i)
    {
        SOCKETSTRUCT*    currentfd = (SOCKETSTRUCT*)(events[i].data.ptr);

        if(NULL != currentfd)
        {
            uint32_t uEvent = events[i].events;

            if(uEvent & EPOLLIN)
            {
                _insertReadable(currentfd);
            }

            if(uEvent & EPOLLOUT)
            {
                _insertWriteable(currentfd);
            }
        }
    }
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_handlerAllRecv()
{
    typename std::list<SOCKETSTRUCT*>::iterator last = m_readableList.end();

    for(typename std::list<SOCKETSTRUCT*>::iterator it = m_readableList.begin(); it != last;)
    {
        SOCKETSTRUCT* client = *it;
        if(client->isReadable())
        {
            EEpollRecvResult eResult = _recvEpollData(*client);
            if(eResult == ERecvCLOSE)
            {
                client->onClose();
                _handleSocketClose(client);
                m_readableList.erase(it++);
            }
            else
            {
                if(eResult & ERecvOK)
                {
                    client->onRecved();
                }

                if(eResult & ERecvEAGIN)
                {
                    // 监听可读事件
                    motifyFdEvent(client, EPOLLIN);
                    m_readableList.erase(it++);
                    _setSocketReadable(*client, false);
                }
                else
                {
                    ++it;
                }
            }
        }
        else
        {
            m_readableList.erase(it++);
        }
    }
}


template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_handlerAllSend()
{
    typename std::list<SOCKETSTRUCT*>::iterator last = m_writeableList.end();

    for(typename std::list<SOCKETSTRUCT*>::iterator it = last; it != last;)
    {
        SOCKETSTRUCT* client = *it;
        if(client->isWriteable())
        {
            EEpollSendResult eResult = _sendEpollData(*client);

            if(eResult == ESendCLOSE)
            {
                client->onClose();
                _handleSocketClose(client);
                m_writeableList.erase(it++);
            }
            else
            {
                if(eResult & ERecvEAGIN)
                {
                    // 监听可写事件
                    motifyFdEvent(client, EPOLLOUT);
                    _setSocketWriteable(*client, false);
                    m_writeableList.erase(it++);
                }
                else
                {
                    ++it;
                }
            }
        }
        else
        {
            m_writeableList.erase(it++);
        }
    }
}


template<typename SOCKETSTRUCT>
bool EpollServer<SOCKETSTRUCT>::poll(long AOverTime)
{
    _handlerAcceptList();
    _handlerEpollEvent(AOverTime);

    // 进行真正读写
    _handlerAllRecv();
    _handlerAllSend();

    _handlerCloseList();

    return true;
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_handleSocketClose(SOCKETSTRUCT* AClient)
{
    delFDEvent(AClient);
    _setStatus(*AClient, ESocketHalfClose);
}


template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_disConnection(SOCKETSTRUCT* AClient)
{
    if (AClient->getStatus() != ESocketHalfClose)
    {
        delFDEvent(AClient);
    }

    sock fd = _getSock(*AClient);

    if(fd != SOCKET_ERROR)
    {
        SocketLib::SocketApi::CloseSocket(fd);
    }

    _initBaseSocket(*AClient);
    m_socketPoll.pushPtrElement(AClient);
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::addFDEvent(SOCKETSTRUCT* AClient, uint32_t AEvent)
{
    sock s = _getSock(*AClient);
    epoll_event ev = { 0, { 0 } };
    ev.events = AEvent;

    ev.data.fd = s;
    ev.data.ptr = AClient;
    epoll_ctl(m_epollFD, EPOLL_CTL_ADD, s, &ev);

    ++m_clientNum;
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::delFDEvent(SOCKETSTRUCT* AClient)
{
    sock s = _getSock(*AClient);
    epoll_event ev = { 0, { 0 } };
    ev.data.fd = s;
    ev.data.ptr = NULL;

    epoll_ctl(m_epollFD, EPOLL_CTL_DEL, s, &ev);
    --m_clientNum;
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::motifyFdEvent(SOCKETSTRUCT* AClient, uint32_t AEvent)
{
    sock s = _getSock(*AClient);
    epoll_event ev = { 0, { 0 } };

    ev.data.fd = s;
    ev.data.ptr = AClient;
    ev.events = AEvent;

    epoll_ctl(m_epollFD, EPOLL_CTL_MOD, s, &ev);
}

template<typename SOCKETSTRUCT>
int EpollServer<SOCKETSTRUCT>::getClientNum()
{
    return m_clientNum;
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_insertReadable(SOCKETSTRUCT* AClient)
{
    m_readableList.push_back(AClient);
    _setSocketReadable(*AClient, true);
}

template<typename SOCKETSTRUCT>
void EpollServer<SOCKETSTRUCT>::_insertWriteable(SOCKETSTRUCT* AClient)
{
    m_writeableList.push_back(AClient);
    _setSocketWriteable(*AClient, true);
}
